﻿/// Name - MyHealth/HealthQuestionaire.cs
/// Description - Displays the Questionaire one page at a time.  Question controls are created
///     dynamically based on database content.
/// Programmer - Dan Yatzeck
/// Date coded - 11/2/2011
/// Arguments - None
/// Variables -
///     _presenter - Object linking to parent Presenter
///     QuestionPage - Current question page to be displayed
///     currentUser - Current user object
/// Files accessed by this code artifact - None
/// Files changed by this code artifact - None
/// I/O -
///     Input - User input of question answers
///     Output - Web page, saved answers
/// Error Handling - None
/// Modifications -
///     1.0 - Initial coding
///     1.1 - Moved validation summary to top, added progress bar, added checkboxlistvalidator from
///         http://scottonwriting.net/sowBlog/CodeProjects.htm
/// Known Faults -
///     1.0 - Inefficient code could lead to unknown problems, some of this code should be in the
///         presenter and queried
///     1.1 - Same as 1.0, will throw error if no questions are loaded (div by 0), getQuestions 
///         method has really poor cohesion which could cause regression faults

using System;
using Microsoft.Practices.ObjectBuilder;
using System.Collections.Generic;
using Common;
using System.Web.UI;
using System.Web.UI.WebControls;
using skmValidators;

namespace CSC440TeamOne.MyHealth.Views
{
    /// <summary>
    /// Display health questionaire and accept user input
    /// </summary>
	public partial class HealthQuestionaire : Microsoft.Practices.CompositeWeb.Web.UI.Page, IHealthQuestionaireView
	{
		private HealthQuestionairePresenter _presenter;
        private int QuestionPage;
        private User currentUser;

        /// <summary>
        /// Page Load
        /// Get current user, current page, and related questions for display
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
		protected void Page_Load(object sender, EventArgs e)
		{
            this._presenter.OnViewLoaded();
            
            // Get current user
            //Session["currentUser"] = _presenter.LoadCurrentUser();
            //new User("Dan", "Yatzeck", "dyatzeck@gmail.com", DateTime.Today, "Male", "White", "53149", "USA");
            if (Session["currentUser"] == null)
            {
                LiteralControl literal = new LiteralControl("Please log in or sign up to proceed.");
                pnlQuestionaire.Controls.Add(literal);
                return;
            }
            else
            {
                this.currentUser = Session["currentUser"] as User;
            }

            // If not postback, this is the first page in the questionaire or the accessing a partially
            // completed questionaire
			if (!this.IsPostBack)
			{
				this._presenter.OnViewInitialized();

                // If completed, redirect
                if (currentUser.QuestionaireCompleted)
                {
                    Response.Redirect("HealthQuestionaireFinished.aspx");
                }

                // Put user on correct page
                if (currentUser.QuestionaireLastPageCompleted > 0)
                {
                    ViewState["questionPage"] = currentUser.QuestionaireLastPageCompleted;
                    this.QuestionPage = currentUser.QuestionaireLastPageCompleted;
                }
                else
                {
                    ViewState["questionPage"] = 1;
                    this.QuestionPage = 1;
                }

                // Redirect to completion when done
                if (_presenter.getMaxPages() < this.QuestionPage)
                {
                    this.currentUser.QuestionaireCompleted = true;
                    Session["currentUser"] = this.currentUser;

                    Response.Redirect("HealthQuestionaireFinished.aspx");
                }

                // Get questions for the current page
                getQuestions(this.QuestionPage);
			}

            // Postback, user came from previous questionaire page
            if (this.IsPostBack)
            {
                // Save answers from previous page
                saveAnswers();
               
                int? questionPage;

                // Get current page number
                questionPage = ViewState["questionPage"] as Int32?;

                if (!questionPage.HasValue)
                {
                    Response.Redirect("Default.aspx");
                }

                // Reset current page on user record, if there was an error then keep it the
                // same, otherwise increment
                if (!Request.Form["__EVENTTARGET"].Contains("QuestionairePageSubmit"))
                    currentUser.QuestionaireLastPageCompleted = (int)questionPage;
                else
                    currentUser.QuestionaireLastPageCompleted = (int)questionPage + 1;

                // Increment
                this.QuestionPage = (int)questionPage + 1;

                
                // Redirect to completion when done
                if (_presenter.getMaxPages() < this.QuestionPage)
                {
                    this.currentUser.QuestionaireCompleted = true;
                    Session["currentUser"] = this.currentUser;

                    Response.Redirect("HealthQuestionaireFinished.aspx");
                }

                // Get questions for the current page
                getQuestions(QuestionPage);

                // Save current page to view state for next postback
                ViewState["questionPage"] = QuestionPage;
            }
		}

        /// <summary>
        /// When this object is instantiated, create the presenter link
        /// </summary>
		[CreateNew]
		public HealthQuestionairePresenter Presenter
		{
			get
			{
				return this._presenter;
			}
			set
			{
				if(value == null)
					throw new ArgumentNullException("value");

				this._presenter = value;
				this._presenter.View = this;
			}
		}

        /// <summary>
        /// Get Questions for current page and add them to the screen
        /// </summary>
        /// <param name="questionPage">Page number</param>
        private void getQuestions(int questionPage)
        {
            // Get page questions from the presenter
            List<Question> questions = _presenter.getQuestions(questionPage);
            
            // Get max page
            int maxPage = _presenter.getMaxPages();

            // Add progress bar using an html table 
            int progressBarWidth = 300;
            decimal progressPercent = 100 * this.QuestionPage / (maxPage + 1);
            Label lblProgressBar = new Label();
            lblProgressBar.ID = "lblProgressBar";
            lblProgressBar.Text = "Questionaire Progress - " + progressPercent + "%";
            pnlQuestionaire.Controls.Add(lblProgressBar);
            pnlQuestionaire.Controls.Add(new LiteralControl(@"

                    <table style=""border-style: solid; border-width: 1px;"" cellpadding='0' cellspacing='0'>
                        <tr>
                            <td width='" + progressBarWidth+@"px'>
                                <img src='../images/progressbar02.gif' width='" + progressBarWidth * progressPercent / 100 +@"px' height='10px'>
                            </td>
                            
                        </tr>
                    </table>
            "));
            pnlQuestionaire.Controls.Add(new LiteralControl("<br />"));


            // Process special response to question 1
            string answer1 = getAnswerFromForm(1);
            if (!String.IsNullOrEmpty(answer1))
            {
                if (answer1 == "Yes" || this.currentUser.Age > 40)
                {
                    questions.RemoveAt(0);
                }
                else
                {
                    questions.RemoveAt(1);
                }
            }

            // Process special response to survey
            string answersurvey = getAnswerFromForm(1003);
            if (!String.IsNullOrEmpty(answersurvey))
            {
                if (answersurvey == "No")
                {
                    Response.Redirect("CancelQuestionaire.aspx");
                }
            }

            // Add page label (Page 1, 2...)
            Label pageLabel = new Label();
            pageLabel.Text = "Page " + QuestionPage.ToString();
            pageLabel.Font.Bold = true;
            pnlQuestionaire.Controls.Add(pageLabel);
            pnlQuestionaire.Controls.Add(new LiteralControl("<br />"));

            // Validation summary at the top of each page
            ValidationSummary validationSummary = new ValidationSummary();
            validationSummary.ForeColor = System.Drawing.Color.Red;
            pnlQuestionaire.Controls.Add(validationSummary);

            pnlQuestionaire.Controls.Add(new LiteralControl("<br />"));

            // Add question/answer controls to the screen
            foreach (Question question in questions)
            {
                // Question text is always a label
                Label label = new Label();
                label.Text = question.QuestionText;

                // Create answer controls based on answer type in Question object
                switch (question.AnswerControlType)
                {
                    case Question.Types.RadioButton:

                        RadioButtonList answercontrolRADIO = new RadioButtonList();
                        answercontrolRADIO.ID = "Question" + question.QuestionID.ToString();
                        // Radio button assumes answer controls are contained in ChildItems
                        foreach (Question item in question.ChildItems)
                        {
                            ListItem listitem = new ListItem();
                            listitem.Value = item.QuestionText;
                            answercontrolRADIO.Items.Add(listitem);
                        }
                        // Add Required validator
                        if (question.Required)
                        {
                            RequiredFieldValidator validator = new RequiredFieldValidator();
                            validator.ID = "Question" + question.QuestionID.ToString() + "Validator";
                            validator.ForeColor = System.Drawing.Color.Red;
                            validator.ControlToValidate = answercontrolRADIO.ID;
                            validator.Text = "*";
                            validator.ErrorMessage = question.RequiredMessage;
                            validator.Display = ValidatorDisplay.Dynamic;
                            validator.Enabled = false;
                            pnlQuestionaire.Controls.Add(validator);
                        }
                        // Add RegEx validator
                        if (!String.IsNullOrEmpty(question.RegExValidation))
                        {
                            RegularExpressionValidator regex = new RegularExpressionValidator();
                            regex.ID = "Question" + question.QuestionID.ToString() + "Regex";
                            regex.ForeColor = System.Drawing.Color.Red;
                            regex.ControlToValidate = answercontrolRADIO.ID;
                            regex.Text = "*";
                            regex.ValidationExpression = question.RegExValidation;
                            regex.ErrorMessage = question.RegExMessage;
                            regex.Display = ValidatorDisplay.Dynamic;
                            regex.Enabled = false;
                            pnlQuestionaire.Controls.Add(regex);
                        }

                        // Add question text after the validators
                        pnlQuestionaire.Controls.Add(label);

                        // Add help text after question text
                        if (question.HelpText != null)
                        {
                            pnlQuestionaire.Controls.Add(new LiteralControl(this.getHelpTextControlCode(question)));
                        }

                        // Add answer controls
                        pnlQuestionaire.Controls.Add(answercontrolRADIO);
                        
                        break;

                    case Question.Types.TextBox:

                        TextBox answercontrolTEXT = new TextBox();
                        answercontrolTEXT.ID = "Question" + question.QuestionID.ToString();
                        // Add Required validator
                        if (question.Required)
                        {
                            RequiredFieldValidator validator = new RequiredFieldValidator();
                            validator.ID = "Question" + question.QuestionID.ToString() + "Validator";
                            validator.ForeColor = System.Drawing.Color.Red;
                            validator.ControlToValidate = answercontrolTEXT.ID;
                            validator.Text = "*";
                            validator.ErrorMessage = question.RequiredMessage;
                            validator.Enabled = false;
                            validator.Display = ValidatorDisplay.Dynamic;
                            pnlQuestionaire.Controls.Add(validator);
                        }
                        // Add RegEx validator
                        if (!String.IsNullOrEmpty(question.RegExValidation))
                        {
                            RegularExpressionValidator regex = new RegularExpressionValidator();
                            regex.ID = "Question" + question.QuestionID.ToString() + "Regex";
                            regex.ForeColor = System.Drawing.Color.Red;
                            regex.ControlToValidate = answercontrolTEXT.ClientID;
                            regex.Text = "*";
                            regex.ValidationExpression = question.RegExValidation;
                            regex.ErrorMessage = question.RegExMessage; 
                            regex.Display = ValidatorDisplay.Dynamic;
                            regex.Enabled = false;
                            pnlQuestionaire.Controls.Add(regex);
                        }

                        // Add question text after the validators
                        pnlQuestionaire.Controls.Add(label);

                        // Add help text after question text
                        if (question.HelpText != null)
                        {
                            pnlQuestionaire.Controls.Add(new LiteralControl(this.getHelpTextControlCode(question)));
                        }

                        // Add answer controls
                        pnlQuestionaire.Controls.Add(new LiteralControl("<br />"));
                        pnlQuestionaire.Controls.Add(answercontrolTEXT);
                        
                        break;

                    case Question.Types.CheckBox:

                        CheckBoxList answercontrolCHECK = new CheckBoxList();
                        answercontrolCHECK.ID = "Question" + question.QuestionID.ToString();
                        // Checkbox assumes answer controls are contained in ChildItems
                        foreach (Question item in question.ChildItems)
                        {
                            ListItem listitem = new ListItem();
                            listitem.Value = item.QuestionText;
                            answercontrolCHECK.Items.Add(listitem);
                        }
                        // Add Required validator
                        if (question.Required)
                        {
                            // RequiredFieldValidator does not work with CheckBoxLists, so had to import
                            // custom control
                            CheckBoxListValidator validator = new CheckBoxListValidator();
                            validator.ID = "Question" + question.QuestionID.ToString() + "Validator";
                            validator.ForeColor = System.Drawing.Color.Red;
                            validator.ControlToValidate = answercontrolCHECK.ID;
                            validator.Text = "*";
                            validator.ErrorMessage = question.RequiredMessage;
                            validator.Display = ValidatorDisplay.Dynamic;
                            validator.Enabled = false;
                            pnlQuestionaire.Controls.Add(validator);
                        }

                        // Add question text after the validators
                        pnlQuestionaire.Controls.Add(label);

                        // Add help text after question text
                        if (question.HelpText != null)
                        {
                            pnlQuestionaire.Controls.Add(new LiteralControl(this.getHelpTextControlCode(question)));
                        }

                        // Add answer controls
                        pnlQuestionaire.Controls.Add(answercontrolCHECK);
                        
                        break;

                    case Question.Types.Literal:

                        // Literal control is straight HTML
                        LiteralControl answercontrolLITERAL = new LiteralControl();
                        answercontrolLITERAL.ID = "Question" + question.QuestionID.ToString();
                        answercontrolLITERAL.Text = question.AnswerText;

                        // Add header text
                        pnlQuestionaire.Controls.Add(label);

                        // Add help text after header text
                        if (question.HelpText != null)
                        {
                            pnlQuestionaire.Controls.Add(new LiteralControl(this.getHelpTextControlCode(question)));
                        }

                        // Add literal
                        pnlQuestionaire.Controls.Add(answercontrolLITERAL);

                        break;
                }

                // Space between questions
                pnlQuestionaire.Controls.Add(new LiteralControl("<br />"));
                pnlQuestionaire.Controls.Add(new LiteralControl("<br />"));

            }

            // Add submit button with event handler
            Button submitButton = new Button();
            submitButton.ID = "QuestionairePageSubmit";
            submitButton.Text = "Next";
            submitButton.Click += new EventHandler(submitButton_Click);
            pnlQuestionaire.Controls.Add(submitButton);

        }

        /// <summary>
        /// Returns raw HTML containing the javascript for each question HelpText popup message
        /// </summary>
        /// <param name="question">Question object containing Help Text attribute</param>
        /// <returns>HTML code for creating the popup message</returns>
        private string getHelpTextControlCode(Question question)
        {
            string popupscript = @"
                <style>
                    #helpdiv_question" + question.QuestionID.ToString() + @" { position:absolute; top:auto; left:auto; width:auto; height:auto; text-align:left; vertical-align:middle; z-index: 10000; background-color:#FFFFFF; }
                </style>
                <script type=""text/javascript"">
                    function expand_question" + question.QuestionID.ToString() + @"() {
                        var thediv;
                        var header;
                        var description;

                        thediv = document.getElementById('helpdiv_question" + question.QuestionID.ToString() + @"');
                        header = '" + question.HelpText.Header + @"';
                        description ='" + question.HelpText.Description + @"';
                            
                        if (thediv.style.display == ""none"") {
                            thediv.style.display = """";
                            thediv.innerHTML = ""<table style='border-style: solid; border-width: 1px;' frame='box' width='400px' height='150px'><tr><td align='left' valign='top' width='100%' height='100%'><font style='font-weight:bold;'>"" + header + ""</font><br>"" + description + ""<br><br><a href='#' onclick='return expand_question" + question.QuestionID.ToString() + @"();'>CLOSE</a></td></tr></table>"";
                        }
                        else {
                            thediv.style.display = ""none"";
                            thediv.innerHTML = '';
                        }
        
                        return false;
                    }
                </script>
            ";

            string href = @"
                <a href='#' id='helppopuplink_question" + question.QuestionID.ToString() + @"' onclick='return expand_question" + question.QuestionID.ToString() + @"();'>
                    <img src=""..\Images\question_mark_small.jpg"" width=""15px"" height=""15px"" /></a>
                <div id=""helpdiv_question" + question.QuestionID.ToString() + @""" style=""display: none;""></div>
                <br />
            ";

            return popupscript + href;
        }

        /// <summary>
        /// Sends question ID and its answer to presenter for saving to the database
        /// </summary>
        private void saveAnswers()
        {
            System.Collections.Specialized.NameValueCollection collection = Request.Form;

            // Search through previous postback form
            foreach (String str in collection.AllKeys)
            {
                // for each "Question" control, get answer and save
                if (str.Contains("Question"))
                {
                    string questionIDstr = str.Substring(str.IndexOf("Question") + 8);
                    string answer = collection[str];

                    // checkboxes have the answer ID at the end of the ID
                    if (questionIDstr.Contains("$"))
                    {
                        string[] splitstr = questionIDstr.Split('$');
                        int questionID;
                        int answerID;
                        bool QisInt = Int32.TryParse(splitstr[0], out questionID);
                        bool AisInt = Int32.TryParse(splitstr[1], out answerID);
                        if (QisInt && AisInt)
                        {
                            _presenter.saveAnswer(questionID, answer);
                        }
                    }
                    else
                    {
                        int questionID;
                        bool isInt = Int32.TryParse(questionIDstr, out questionID);
                        if (isInt)
                        {
                            _presenter.saveAnswer(questionID, answer);
                        }
                    }
                    

                }
            }
        }

        /// <summary>
        /// Analyzes previous postback form items to get answered question.
        /// </summary>
        /// <param name="questionID">ID of the question for which to be searched</param>
        /// <returns>Answer text to the question ID provided, or empty string</returns>
        private string getAnswerFromForm(int questionID)
        {
            string answer = "";
            System.Collections.Specialized.NameValueCollection collection = Request.Form;

            foreach (String str in collection.AllKeys)
            {
                //Response.Write(str + "<br>");
                if (str.Contains("Question") && str.Length >= 8 + questionID.ToString().Length)
                {
                    if (str.Substring(str.Length - (8+questionID.ToString().Length)) == "Question"+questionID.ToString())
                    {
                        answer = collection[str];
                        break;
                    }
                }
            }
            return answer;
        }

        /// <summary>
        /// Submit button event handler
        /// Currently does nothing besides postback.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void submitButton_Click(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Override render function to enable validators.  Based on the page lifecycle of ASP.NET, the
        /// page_load happens, which creates the validators, then the control code is executed, then the 
        /// page is rendered.  When the control code is executed, all the validators are triggered with
        /// blank values, and validation summary and all validation messages are displayed.  To get around
        /// this, the validators are disabled on creation, and enabled here during rendering.
        /// </summary>
        /// <param name="writer"></param>
        protected override void Render(HtmlTextWriter writer)
        {
            // Due to validators being created during page_load, postback triggers the validators after creation but before display.
            // Need to enable the validators after this happens.
            foreach(Control ctrl in pnlQuestionaire.Controls)
            {
                if (ctrl is RequiredFieldValidator)
                {
                    ((RequiredFieldValidator)ctrl).Enabled = true;
                }
                else if (ctrl is RegularExpressionValidator)
                {
                    ((RegularExpressionValidator)ctrl).Enabled = true;
                }
                else if (ctrl is CheckBoxListValidator)
                {
                    ((CheckBoxListValidator)ctrl).Enabled = true;
                }
            }

            base.Render(writer);
        }
	}
}

